Stability of Runge-Kutta Method#

강좌: 수치해석

안정성#

시간 간격에 따라 정확도 뿐 아니라 알고리즘이 발산할 수 있다. 이는 수치 안정성과 관계된다.

안정성을 분석하기 위해 Model problem을 생각한다.

\[ \frac{dy}{dt}=f(y,t) = f(y_0, t_0) + (t-t_0)f_t + (y - y_0) f_y + ... = \lambda y + Others \]
\[ \frac{dy}{dt}= \lambda y, ~~~~\lambda = \lambda_R + i \lambda_i \]

\(\lambda_R < 0\) 인 경우 이 미분방정식은 해가 제한되어 (bounded) 있다.

Sympy#

sympy 는 Symbolic Math 프로그램으로 수식 연산을 지원한다.

이를 이용하면 수식 전개에 활용할 수 있다.

%matplotlib inline
from matplotlib import pyplot as plt

import numpy as np

plt.style.use('ggplot')
plt.rcParams['figure.dpi'] = 150
import sympy as sy

# Symbolic Math
lam = sy.Symbol('lambda')
h = sy.Symbol('h')
t = sy.Symbol('t')
y = sy.Symbol('y')


# Define model function y'= lambda y
def ff(t, y):
    return lam*y

Explicit Euler Method#

# Expression
expr = sy.simplify((y + h*ff(t, y))/y)

print(expr)

# Sig
z = sy.Symbol('z')
sigf = sy.lambdify(z, expr.subs(h*lam, z), 'numpy')

# Make grid
xx = np.linspace(-3, 3, 201)
yy = np.linspace(-3, 3, 201)
X, Y = np.meshgrid(xx, yy)
z = X + Y*1j

# Amplication factor of Explicit Euler (z=lambda h)
sig = sigf(z)

# Same scale of x and y
plt.axis('equal')

# Stability region
plt.contourf(X,Y,abs(sig), levels=[0, 1])

# Title
plt.title('Stability region of Explicit Euler')
h*lambda + 1
Text(0.5, 1.0, 'Stability region of Explicit Euler')
../_images/a7a4c271454837791c4d5e2eab1cf5fd5eae19a93277f826458f67203d79180e.png

2nd-order Runge-Kutta Method#

# Coefficient for Heun's
c2, a21 = 1, 1
b1, b2 = 0.5, 0.5

# Coefficient for Midpoint
#c2, a21 = 1/2, 1/2
#b1, b2 = 0.0, 1.0

k1 = ff(t, y)
k2 = ff(t + c2*h, y+ h*a21*k1)

# Factor expression
expr = sy.simplify((y+ h*(b1*k1 + b2*k2)) / y)
print(expr)

# Sig
z = sy.Symbol('z')
sigf = sy.lambdify(z, expr.subs(h*lam, z), 'numpy')

# Make grid
xx = np.linspace(-3, 3, 201)
yy = np.linspace(-3, 3, 201)
X, Y = np.meshgrid(xx, yy)
z = X + Y*1j

# Amplication factor of Explicit Euler (z=lambda h)
sig = sigf(z)

# Same scale of x and y
plt.axis('equal')

# Stability region
plt.contourf(X,Y,abs(sig), levels=[0, 1])

# Title
plt.title('Stability region of RK2')
0.5*h*lambda*(h*lambda + 2) + 1
Text(0.5, 1.0, 'Stability region of RK2')
../_images/22d9916027a0ebf814e3d70d30f121d4065223eadfebf4956fc21b668af19bcf.png

4th-order Runge-Kutta Method#

# Coefficient for classical RK4
c2, c3, c4 = 0.5, 0.5, 1.0
a21 = 0.5
a32 = 0.5
a43 = 1.0
b1, b2, b3, b4 = 1/6, 1/3, 1/3, 1/6

k1 = ff(t, y)
k2 = ff(t + c2*h, y+ h*a21*k1)
k3 = ff(t + c3*h, y+ h*a32*k2)
k4 = ff(t + c4*h, y+ h*a43*k3)

# Factor expression
expr = sy.simplify((y+ h*(b1*k1 + b2*k2 + b3*k3 + b4*k4)) / y)
print(expr)

# Sig
z = sy.Symbol('z')
sigf = sy.lambdify(z, expr.subs(h*lam, z), 'numpy')

# Make grid
xx = np.linspace(-3, 3, 201)
yy = np.linspace(-3, 3, 201)
X, Y = np.meshgrid(xx, yy)
z = X + Y*1j

# Amplication factor of Explicit Euler (z=lambda h)
sig = sigf(z)

# Same scale of x and y
plt.axis('equal')

# Stability region
plt.contourf(X,Y,abs(sig), levels=[0, 1])

# Title
plt.title('Stability region of RK4')
0.0416666666666667*h**4*lambda**4 + 0.166666666666667*h**3*lambda**3 + 0.5*h**2*lambda**2 + 1.0*h*lambda + 1.0
Text(0.5, 1.0, 'Stability region of RK4')
../_images/8ea3497d7b821e0be26bf836f31dba177f8d335e417ac08b09d5fb6dacfe481a.png